home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / Development Platforms / AppsToGo / AppsToGo.src / DTS.Lib / File2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-18  |  30.5 KB  |  1,039 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         DTS.Lib
  5. ** File:            file2.c
  6. ** Some code from:  Traffic Light 2.0 version, by Keith Rollin & John Harvey
  7. ** Modified by:     Eric Soldan
  8. **
  9. ** Copyright © 1990-1993 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21.  
  22.  
  23. /*****************************************************************************/
  24.  
  25.  
  26.  
  27. #include "DTS.Lib2.h"
  28. #include "DTS.Lib.protos.h"
  29.  
  30. #ifndef __ERRORS__
  31. #include <Errors.h>
  32. #endif
  33.  
  34. #ifndef __FILES__
  35. #include <Files.h>
  36. #endif
  37.  
  38. #if __MOVIESUPPORT__
  39.  
  40. #ifndef __IMAGECOMPRESSION__
  41. #include <ImageCompression.h>
  42. #endif
  43.  
  44. #ifndef __MOVIES__
  45. #include <Movies.h>
  46. #endif
  47.  
  48. #endif
  49.  
  50. #ifndef __PACKAGES__
  51. #include <Packages.h>
  52. #endif
  53.  
  54. #ifndef __RESOURCES__
  55. #include <Resources.h>
  56. #endif
  57.  
  58. #ifndef __STRING__
  59. #include <String.h>
  60. #endif
  61.  
  62. #ifndef __TOOLUTILS__
  63. #include <ToolUtils.h>
  64. #endif
  65.  
  66.  
  67.  
  68. /*****************************************************************************/
  69.  
  70.  
  71.  
  72. extern OSType        gDocCreator;    /* Initialized to gSignature by Init. */
  73. extern long            gAppWindowAttr;    /* Initialized by app in Window.c. */
  74. extern long            gQTVersion;        /* Initialized by Utilities.c in InitQuickTime. */
  75.  
  76. extern TreeObjHndl    gWindowFormats;    /* If non-nil, then get descriptions of windows from here. */
  77.  
  78. extern short        gTypeListLen;    /* Initialized by app in File.c. */
  79. extern OSType        *gTypeListPtr;    /* Initialized by app in File.c. */
  80.  
  81. FileFilterProcPtr    gSFGetFileFilter;
  82.  
  83. static OSErr        Create_OpenFile(FSSpec *file, short *refNum, OSType sftype);
  84.  
  85.  
  86.  
  87. /*****************************************************************************/
  88. /*****************************************************************************/
  89.  
  90.  
  91.  
  92. /* This function disposes of the document.  It checks to see if a file is
  93. ** currently open for the document.  If it is, then the document is closed.
  94. ** Once there is no open file for the document, the memory occupied by the
  95. ** document is released. */
  96.  
  97. #pragma segment File
  98. OSErr    DisposeDocument(FileRecHndl frHndl)
  99. {
  100.     OSErr        err, err2;
  101.     short        refNum;
  102.     WindowPtr    window;
  103.     Movie        movie;
  104.  
  105.     err = noErr;
  106.  
  107.     if (frHndl) {
  108.  
  109.         if ((refNum = (*frHndl)->fileState.refNum) != kInvalRefNum) {        /* If file open... */
  110.  
  111.             if ((*frHndl)->fileState.sfType == MovieFileType)        /* If movie file... */
  112.                 err = CloseMovieFile(refNum);                        /* Close it. */
  113.  
  114.             else                                                    /* If not movie file... */
  115.                 err = FSClose(refNum);                                /* Close it.       */
  116.         }
  117.  
  118.         CloseDocResFile(frHndl);                    /* Close resource fork, if opened. */
  119.  
  120.         window = (*frHndl)->fileState.window;
  121.         err2    = DoFreeDocument(frHndl);            /* Free all application-specific document ram. */
  122.  
  123.         if (movie = (*frHndl)->fileState.movie)
  124.             DisposeMovie(movie);                    /* If we have a movie, dispose it. */
  125.  
  126.         if (window)
  127.             SetWRefCon(window, (long)nil);            /* Mark window as no longer having a document. */
  128.  
  129.         if (!err)
  130.             err = err2;
  131.  
  132.         DisposeHandle((Handle)frHndl);                /* Release memory for the document handle. */
  133.     }
  134.  
  135.     return(err);
  136. }
  137.  
  138.  
  139.  
  140. /*****************************************************************************/
  141.  
  142.  
  143.  
  144. /* This function creates a new document.  A handle is created as the
  145. ** reference to the document.  Header information is placed in this handle.
  146. ** The application-specific data follows this header information.  The
  147. ** handle is returned (or nil upon failure), and typically the handle is
  148. ** then stored in the refCon field of the window.  Note that this is a
  149. ** convention, and is not mandatory.  This allows a document to exist that
  150. ** has no window.  A document with no window is useful when the application
  151. ** is called from the finder in response to a print request.  The document
  152. ** can be loaded and printed without involving a window on the screen. */
  153.  
  154. #pragma segment File
  155. OSErr    NewDocument(FileRecHndl *returnHndl, OSType sftype, Boolean incTitleNum)
  156. {
  157.     long                size;
  158.     FileRecHndl            frHndl;
  159.     FileRecPtr            frPtr;
  160.     Str255                untitled;
  161.     StringPtr            pstr;
  162.     OSErr                err;
  163.     short                i;
  164.     Movie                movie;
  165.     TreeObjHndl            wobj;
  166.     PositionWndProcPtr    windowPlacementProc;
  167.     static short        untitledCount;
  168.  
  169.     if (!sftype) {
  170.         if (returnHndl == (FileRecHndl *)-1)
  171.             --untitledCount;
  172.         if (!returnHndl)
  173.             untitledCount = 0;
  174.         return(noErr);
  175.     }
  176.  
  177.     if (returnHndl)
  178.         *returnHndl = nil;
  179.  
  180.     err  = memFullErr;                /* Assume that we will fail. */
  181.  
  182.     size = InitDocumentSize(sftype);
  183.         /* Call the application and ask it how big the frHndl should be for
  184.         ** this document type.  We can't know, so we'll ask. */
  185.  
  186.     if (frHndl = (FileRecHndl)NewHandleClear(size)) {
  187.         /* Create (or try to) the frHndl, initialized to all 0's */
  188.  
  189.         if (returnHndl)
  190.             *returnHndl = frHndl;
  191.  
  192.         windowPlacementProc = StaggerWindow;
  193.         wobj = nil;
  194.         if (gWindowFormats) {
  195.             for (i = 0; i < (*gWindowFormats)->numChildren; ++i) {
  196.                 wobj = GetChildHndl(gWindowFormats, i);
  197.                 if (sftype == mDerefWFMT(wobj)->sfType) {
  198.                     windowPlacementProc = nil;
  199.                         /* If using 'WFMT' descriptions, this will be fully determined later. */
  200.                     pcpy(untitled, (StringPtr)mDerefWFMT(wobj)->title);
  201.                     break;
  202.                 }
  203.                 wobj = nil;
  204.             }
  205.         }
  206.         if (!wobj) {
  207.             for (i = gTypeListLen; --i;) if (sftype == gTypeListPtr[i]) break;
  208.                 /* Walk the typeList to find this file type.  We are interested in
  209.                 ** where we find the entry.  The position we find it is used as a
  210.                 ** string number into the rDefaultTitles STR# resource.  We get
  211.                 ** an individual string from this location.  This allows us to
  212.                 ** have different default titles for different document types. */
  213.     
  214.             for (++i; i; i--) {
  215.                 GetIndString(untitled, rDefaultTitles, i);
  216.                 if (untitled[0]) break;        /* Quit if we succeeded at getting one. */
  217.             }
  218.         }
  219.  
  220.         (*frHndl)->fileState.modNum = GetModNum();
  221.             /* In case GetModNum gets moved to another code segment, set this value
  222.             ** prior to dereferencing frHndl into frPtr. */
  223.  
  224.         frPtr = *frHndl;
  225.         frPtr->fileState.sfType                  = sftype;
  226.         frPtr->fileState.modTick                 = TickCount();
  227.         frPtr->fileState.refNum                  = kInvalRefNum;
  228.         frPtr->fileState.resRefNum               = kInvalRefNum;
  229.         frPtr->fileState.fss.vRefNum             = kInvalVRefNum;
  230.         frPtr->fileState.windowID                = rWindow;
  231.             /* The above sets the fileState constants for the document.  Note
  232.             ** that we use a default 'WIND' ID for the expected window resource.
  233.             ** This can be changed later, if the default isn't good enough. */
  234.  
  235.         if (wobj) {
  236.             frPtr->fileState.windowID      = mDerefWFMT(wobj)->windowID;
  237.             frPtr->fileState.attributes    = mDerefWFMT(wobj)->attributes;
  238.             frPtr->fileState.hScrollIndent = mDerefWFMT(wobj)->hScrollIndent;
  239.             frPtr->fileState.vScrollIndent = mDerefWFMT(wobj)->vScrollIndent;
  240.             frPtr->fileState.leftSidebar   = mDerefWFMT(wobj)->leftSidebar;
  241.             frPtr->fileState.topSidebar    = mDerefWFMT(wobj)->topSidebar;
  242.                 /* Set window attributes as described in resource. */
  243.         }
  244.         else
  245.             frPtr->fileState.attributes = gAppWindowAttr;
  246.                 /* Set window attributes for the main document type. If the document
  247.                 ** is not the main type, then the application's InitDocument function
  248.                 ** will have to change it. */
  249.  
  250.         frPtr->fileState.getDocWindow        = windowPlacementProc;
  251.         frPtr->fileState.adjustMenuItemsProc = AdjustMenuItems;
  252.         frPtr->fileState.doMenuItemProc      = DoMenuItem;
  253.         switch (frPtr->fileState.attributes & (kwIsPalette | kwIsModalDialog)) {
  254.             case kwIsPalette:
  255.                 frPtr->fileState.calcFrameRgnProc  = PaletteCalcFrameRgn;
  256.                 frPtr->fileState.contentClickProc  = PaletteContentClick;
  257.                 frPtr->fileState.contentKeyProc    = PaletteContentKey;
  258.                 frPtr->fileState.drawFrameProc     = PaletteDrawFrame;
  259.                 frPtr->fileState.freeDocumentProc  = PaletteFreeDocument;
  260.                 frPtr->fileState.freeWindowProc    = PaletteFreeWindow;
  261.                 frPtr->fileState.imageProc         = PaletteImageDocument;
  262.                 frPtr->fileState.initContentProc   = PaletteInitContent;
  263.                 frPtr->fileState.readDocumentProc  = nil;
  264.                 frPtr->fileState.resizeContentProc = PaletteResizeContent;
  265.                 frPtr->fileState.scrollFrameProc   = PaletteScrollFrame;
  266.                 frPtr->fileState.undoFixupProc     = PaletteUndoFixup;
  267.                 frPtr->fileState.windowCursorProc  = PaletteWindowCursor;
  268.                 frPtr->fileState.writeDocumentProc = nil;
  269.                 break;
  270.             case kwIsModalDialog:
  271.                 frPtr->fileState.calcFrameRgnProc    = DialogCalcFrameRgn;
  272.                 frPtr->fileState.contentClickProc    = DialogContentClick;
  273.                 frPtr->fileState.contentKeyProc      = DialogContentKey;
  274.                 frPtr->fileState.drawFrameProc       = DialogDrawFrame;
  275.                 frPtr->fileState.freeDocumentProc    = DialogFreeDocument;
  276.                 frPtr->fileState.freeWindowProc      = DialogFreeWindow;
  277.                 frPtr->fileState.imageProc           = DialogImageDocument;
  278.                 frPtr->fileState.initContentProc     = DialogInitContent;
  279.                 frPtr->fileState.readDocumentProc    = nil;
  280.                 frPtr->fileState.resizeContentProc   = DialogResizeContent;
  281.                 frPtr->fileState.scrollFrameProc     = DialogScrollFrame;
  282.                 frPtr->fileState.undoFixupProc       = DialogUndoFixup;
  283.                 frPtr->fileState.windowCursorProc    = DialogWindowCursor;
  284.                 frPtr->fileState.writeDocumentProc   = nil;
  285.                 frPtr->fileState.adjustMenuItemsProc = DialogAdjustMenuItems;
  286.                 frPtr->fileState.doMenuItemProc      = DialogDoMenuItem;
  287.                 break;
  288.             default:
  289.                 frPtr->fileState.calcFrameRgnProc  = CalcFrameRgn;
  290.                 frPtr->fileState.contentClickProc  = ContentClick;
  291.                 frPtr->fileState.contentKeyProc    = ContentKey;
  292.                 frPtr->fileState.drawFrameProc     = DrawFrame;
  293.                 frPtr->fileState.freeDocumentProc  = FreeDocument;
  294.                 frPtr->fileState.freeWindowProc    = FreeWindow;
  295.                 frPtr->fileState.imageProc         = ImageDocument;
  296.                 frPtr->fileState.initContentProc   = InitContent;
  297.                 frPtr->fileState.readDocumentProc  = ReadDocument;
  298.                 frPtr->fileState.resizeContentProc = ResizeContent;
  299.                 frPtr->fileState.scrollFrameProc   = ScrollFrame;
  300.                 frPtr->fileState.undoFixupProc     = UndoFixup;
  301.                 frPtr->fileState.windowCursorProc  = WindowCursor;
  302.                 frPtr->fileState.writeDocumentProc = WriteDocument;
  303.                 break;
  304.         }
  305.  
  306.         frPtr->fileState.windowSizeBounds.left   = kMinWindowWidth;
  307.         frPtr->fileState.windowSizeBounds.top    = kMinWindowHeight;
  308.         frPtr->fileState.windowSizeBounds.right  = kMaxWindowWidth;
  309.         frPtr->fileState.windowSizeBounds.bottom = kMaxWindowHeight;
  310.             /* Default min/max window size for growIcon. */
  311.  
  312.         pstr = frPtr->fileState.fss.name;
  313.         pcpy(pstr, untitled);
  314.         if (pstr[0]) {
  315.             if (incTitleNum)
  316.                 ++untitledCount;
  317.             pcatdec(pstr, untitledCount);
  318.                 /* Create the default document title.  It is stored in the FSSpec,
  319.                 ** as we can't place it in the window title.  We don't have a window
  320.                 ** yet to "title".  This will happen later.  The title is gotten from
  321.                 ** the FSSpec, so we are effectively done. */
  322.         }
  323.  
  324.         err = InitDocument(frHndl);
  325.             /* Call the application for any additional document initialization.
  326.             ** Other handles may need to be allocated.  The default values above
  327.             ** may be incorrect for a certain document type.  This gives the
  328.             ** application a chance to change any defaults that are incorrect. */
  329.  
  330.         if ((*frHndl)->fileState.sfType == MovieFileType) {
  331.             InitQuickTime();
  332.             if (!gQTVersion) return(paramErr);
  333.             movie = NewMovie(newMovieActive);
  334.             err   = GetMoviesError();
  335.             if (!err) {
  336.                 ClearMovieChanged(movie);
  337.                 (*frHndl)->fileState.movie = movie;
  338.             }
  339.         }
  340.  
  341.         if (err) {
  342.             DisposeHandle((Handle)frHndl);
  343.             if (returnHndl)
  344.                 *returnHndl = nil;
  345.                     /* If the application couldn't complete the document
  346.                     ** initialization, pitch the handle. */
  347.         }
  348.     }
  349.  
  350.     return(err);
  351. }
  352.  
  353.  
  354.  
  355. /*****************************************************************************/
  356.  
  357.  
  358.  
  359. #pragma segment File
  360. OSErr    OpenDocument(FileRecHndl *result, FSSpecPtr fileToOpen, char permission)
  361. {
  362.     StandardFileReply    reply;
  363.     short                refNum;
  364.     FileRecHndl            frHndl;
  365.     OSErr                err;
  366.     FSSpec                myFileSpec;
  367.     DialogPtr            openDialog;
  368.     short                item;
  369.     FInfo                finderInfo;
  370.     Boolean                openMovie;
  371.     Movie                movie;
  372.     static SFTypeList    typeList = {MovieFileType};
  373.  
  374.     *result = nil;        /* Assume we will fail. */
  375.  
  376.     openMovie = false;
  377.     if (fileToOpen == kOpenMovie) {
  378.         if (!gQTVersion) return(paramErr);        /* Can't do movies without QuickTime. */
  379.         fileToOpen = nil;
  380.         openMovie  = true;
  381.     }
  382.  
  383.     if (!fileToOpen) {
  384.         if (openMovie) {
  385.             StandardGetFilePreview(0L, 1, typeList, &reply);
  386.             if (reply.sfGood)
  387.                 myFileSpec = reply.sfFile;
  388.             else
  389.                 return(userCanceledErr);    /* User canceled. */
  390.         }
  391.         else {
  392.             if (DisplayGetFile(&reply, gTypeListLen, gTypeListPtr))    /* Let user pick file. */
  393.                 myFileSpec = reply.sfFile;                            /* User's choice.       */
  394.             else
  395.                 return(userCanceledErr);    /* User canceled. */
  396.         }
  397.     }
  398.     else {
  399.         err = HGetFInfo(fileToOpen->vRefNum, fileToOpen->parID, fileToOpen->name, &finderInfo);
  400.         if (err) return(err);
  401.         reply.sfType = finderInfo.fdType;        /* OSType of file. */
  402.         myFileSpec   = *fileToOpen;                /* Pre-designated file to open. */
  403.     }
  404.  
  405.     err = NewDocument(&frHndl, reply.sfType, false);
  406.     if (err) return(err);
  407.         /* We couldn't create an empty document, so give it up. */
  408.  
  409.     err = HOpenDF(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  410.     if (err == paramErr)
  411.         err = HOpen(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  412.  
  413.     if (err == opWrErr) {
  414.  
  415.         ParamText(myFileSpec.name, nil, nil, nil);
  416.         openDialog = GetCenteredDialog(rOpenReadOnly, nil, nil, (WindowPtr)-1L);
  417.         if (!openDialog) {
  418.             DisposeDocument(frHndl);
  419.             return(err);
  420.         }
  421.  
  422.         OutlineDialogItem(openDialog, kOpenYes);
  423.         DoSetCursor(&qd.arrow);
  424.         UnhiliteWindows();
  425.         ModalDialog((ModalFilterProcPtr)KeyEquivFilter, &item);
  426.         DisposeDialog(openDialog);
  427.         HiliteWindows();
  428.         if (item != kOpenYes) {
  429.             DisposeDocument(frHndl);
  430.             return(userCanceledErr);
  431.         }
  432.  
  433.         (*frHndl)->fileState.readOnly = true;
  434.         permission = fsRdPerm;
  435.         err = HOpenDF(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  436.         if (err == paramErr)
  437.             err = HOpen(myFileSpec.vRefNum, myFileSpec.parID, myFileSpec.name, permission, &refNum);
  438.     }
  439.  
  440.     if (err) {
  441.         DisposeDocument(frHndl);
  442.         return(err);
  443.     }
  444.  
  445.     if ((*frHndl)->fileState.sfType == MovieFileType) {
  446.         FSClose(refNum);                            /* Close file, as it wasn't opened as movie. */
  447.         if (movie = (*frHndl)->fileState.movie) {
  448.             DisposeMovie(movie);                    /* NewDocument created an empty movie, */
  449.             (*frHndl)->fileState.movie = nil;        /* so first get rid of it. */
  450.         }
  451.         err = OpenMovieFile(&myFileSpec, &refNum, permission);
  452.         if (err) {
  453.             DisposeDocument(frHndl);
  454.             return(err);
  455.         }
  456.     }
  457.  
  458.     (*frHndl)->fileState.fss    = myFileSpec;
  459.     (*frHndl)->fileState.refNum = refNum;
  460.  
  461.     if (err = DoReadDocument(frHndl)) {
  462.         DisposeDocument(frHndl);
  463.         return(err);
  464.     }
  465.  
  466.     *result = frHndl;
  467.     return(noErr);
  468. }
  469.  
  470.  
  471.  
  472. /*****************************************************************************/
  473.  
  474.  
  475.  
  476. #pragma segment File
  477. OSErr    SaveDocument(FileRecHndl frHndl, WindowPtr window, short saveMode)
  478. {
  479.     Str255                closeOrQuit;
  480.     short                item, refNum, resID;
  481.     long                createFlags;
  482.     StandardFileReply    reply;
  483.     OSErr                err;
  484.     Movie                movie;
  485.     Boolean                doPrompt;
  486.     DialogPtr            saveDialog;
  487.  
  488.     err = noErr;
  489.  
  490. /*    When entering, saveMode is set to the menu command number of the
  491. **    the item that prompted this. Current settings are kSave, kSaveAs,
  492. **    kClose, and kQuit. */
  493.  
  494.     if (saveMode != kSaveAs) {                            /* If not save as...                  */
  495.         if (!(*frHndl)->fileState.docDirty) {            /* If file clean...                      */
  496.             if ((*frHndl)->fileState.refNum)            /* If document has a file...          */
  497.                 if (!(*frHndl)->fileState.readOnly)        /* If we are allowed to touch file... */
  498.                     if ((*frHndl)->fileState.attributes & kwOpenAtOldLoc)
  499.                         DoWriteDocumentHeader(frHndl);
  500.                             /* Write out document location and print record information. */
  501.                             /* Ignore errors, as saving the location is a bonus. */
  502.             return(noErr);                                /* Consider it saved. */
  503.         }
  504.     }
  505.  
  506.     pcpy(reply.sfFile.name, (*frHndl)->fileState.fss.name);
  507.  
  508.     if ((saveMode == kClose) || (saveMode == kQuit)) {
  509.         /* If implicit save... */
  510.  
  511.         GetIndString(closeOrQuit, rFileIOStrings,
  512.                      (saveMode == kClose) ? sWClosing : sQuitting);
  513.         ParamText(reply.sfFile.name, closeOrQuit, nil, nil);
  514.  
  515.         saveDialog = GetCenteredDialog(rYesNoCancel, nil, window, (WindowPtr)-1L);
  516.  
  517.         if (saveDialog) {
  518.             OutlineDialogItem(saveDialog, kSaveYes);
  519.             DoSetCursor(&qd.arrow);
  520.             UnhiliteWindows();
  521.             ModalDialog((ModalFilterProcPtr)KeyEquivFilter, &item);
  522.             DisposeDialog(saveDialog);
  523.             HiliteWindows();
  524.         }
  525.         else
  526.             item = kSaveNo;
  527.                 /* If the dialog isn't displayed, then AppleScript doesn't want it to.
  528.                 ** In this case, we were probably AppleScripted the whole time, so
  529.                 ** the document is an AppleScript-produced document.  The script is
  530.                 ** done with the document, so ditch the document. */
  531.  
  532.         if (item != kSaveYes) {
  533.             err = noErr;
  534.             if (item == kSaveCanceled)
  535.                 err = userCanceledErr;
  536.             return(err);
  537.         }
  538.     }
  539.  
  540.     doPrompt = (
  541.         (saveMode == kSaveAs) ||
  542.         ((*frHndl)->fileState.refNum == kInvalRefNum)
  543.     );
  544.  
  545.     if (doPrompt) {
  546.         /* Prompt with SFGetFile if doing a Save As or have never saved before. */
  547.  
  548.         if (!DisplayPutFile(&reply)) return(userCanceledErr);    /* User canceled the save. */
  549.  
  550.         if ((*frHndl)->fileState.sfType != MovieFileType) {
  551.             if ((*frHndl)->fileState.refNum != kInvalRefNum) {
  552.                 if ((*frHndl)->fileState.sfType != MovieFileType) {
  553.                     CloseDocResFile(frHndl);        /* Close resource fork, if opened. */
  554.                     FSClose((*frHndl)->fileState.refNum);
  555.                 }
  556.             }            /* Close the old file.  Don't respond to any error here because
  557.                         ** the user may be trying to do a save-as because their old file
  558.                         ** is bad.  If we fail to close the old file, and then respond
  559.                         ** to the error, the user won't get the opportunity to save
  560.                         ** their document to a new file. */
  561.  
  562.             (*frHndl)->fileState.refNum      = kInvalRefNum;
  563.             (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  564.             if (err = Create_OpenFile(&reply.sfFile, &refNum, (*frHndl)->fileState.sfType))
  565.                 return(err);
  566.         }
  567.         else {
  568.             createFlags = createMovieFileDeleteCurFile;
  569.             err = CreateMovieFile(&reply.sfFile, gDocCreator, 0, createFlags, &refNum, nil);
  570.             if (err) return(err);
  571.             resID = 0;
  572.             err = AddMovieResource((*frHndl)->fileState.movie, refNum, &resID, nil);
  573.             if (err) return(err);
  574.             (*frHndl)->fileState.movieResID = resID;
  575.         }
  576.  
  577.         (*frHndl)->fileState.fss    = reply.sfFile;        /* This is the new file. */
  578.         (*frHndl)->fileState.refNum = refNum;
  579.  
  580.         if (window)
  581.             NewWindowTitle(window, nil);
  582.     }
  583.     else {
  584.         if ((*frHndl)->fileState.sfType == MovieFileType) {
  585.             movie  = (*frHndl)->fileState.movie;
  586.             refNum = (*frHndl)->fileState.refNum;
  587.             resID  = (*frHndl)->fileState.movieResID;
  588.             err = UpdateMovieResource(movie, refNum, resID, nil);
  589.             if (err) return(err);
  590.         }
  591.     }
  592.  
  593.     if (err = DoWriteDocument(frHndl)) return(err);
  594.  
  595.     (*frHndl)->fileState.docDirty = false;
  596.     (*frHndl)->fileState.readOnly = false;
  597.     return(noErr);
  598. }
  599.  
  600.  
  601.  
  602. /*****************************************************************************/
  603.  
  604.  
  605.  
  606. /* ConvertOldToNewSFReply
  607. **
  608. ** struct StandardFileReply {            struct SFReply {
  609. **     Boolean     sfGood;                <-    Boolean good;
  610. **     Boolean     sfReplacing;        <-    Boolean copy;
  611. **     OSType         sfType;                <-    OSType fType;
  612. **     FSSpec        sfFile;
  613. **                     vRefNum;        <-    real vRefnum from (short vRefNum)
  614. **                     parID;            <-    real dirID from (short vRefNum)
  615. **                     name;            <-    Str63 fName;
  616. **     ScriptCode    sfScript;            <-    iuSystemScript
  617. **     short         sfFlags;            <-    0
  618. **     Boolean     sfIsFolder;            <-    false
  619. **     Boolean     sfIsVolume;            <-    false
  620. **     long        sfReserved1;        <-    0
  621. **     short        sfReserved2;        <-    0
  622. ** };                                    };
  623. */
  624.  
  625. #pragma segment File
  626. void    ConvertOldToNewSFReply(SFReply *oldReply, StandardFileReply *newReply)
  627. {
  628.     OSErr        err;
  629.     long        ignoredProcID;
  630.  
  631.     newReply->sfGood        = oldReply->good;
  632.     newReply->sfReplacing    = oldReply->copy;        /* Correct assignment? */
  633.     newReply->sfType        = oldReply->fType;
  634.  
  635.     err = GetWDInfo(oldReply->vRefNum,
  636.                     &newReply->sfFile.vRefNum,
  637.                     &newReply->sfFile.parID,
  638.                     &ignoredProcID);
  639.     pcpy(newReply->sfFile.name, oldReply->fName);
  640.  
  641.     /* Punt on the rest... */
  642.     newReply->sfScript        = iuSystemScript;
  643.     newReply->sfFlags        = 0;
  644.     newReply->sfIsFolder    = false;
  645.     newReply->sfIsVolume    = false;
  646.     newReply->sfReserved1    = 0;
  647.     newReply->sfReserved2    = 0;
  648. }
  649.  
  650.  
  651.  
  652. /*****************************************************************************/
  653.  
  654.  
  655.  
  656. /* Opens the file specified by the passed FSSpec, creating it if it doesn't
  657. ** already exist. Returns the refnum of the open file to the application.
  658. ** File Manager errors are reported and returned. */
  659.  
  660. #pragma segment File
  661. OSErr    Create_OpenFile(FSSpec *file, short *refNum, OSType sftype)
  662. {
  663.     OSErr    err;
  664.  
  665.     err = HCreate(file->vRefNum, file->parID, file->name, gDocCreator, sftype);
  666.     if (err == dupFNErr) {
  667.  
  668.         /* The user already told Standard File to replace the old file
  669.            so let's get rid of it. */
  670.  
  671.         HDelete(file->vRefNum, file->parID, file->name);
  672.  
  673.         /* Try creating it again. */
  674.         err = HCreate(file->vRefNum, file->parID, file->name, gDocCreator, sftype);
  675.     }
  676.  
  677.     if (!err) {
  678.         err = HOpenDF(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  679.         if (err == paramErr)
  680.             err = HOpen(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  681.         if (err)
  682.             HDelete(file->vRefNum, file->parID, file->name);
  683.     }
  684.  
  685.     return(err);
  686. }
  687.  
  688.  
  689.  
  690. /*****************************************************************************/
  691.  
  692.  
  693.  
  694. /* Simple routine to display a list of files with our file type. */
  695.  
  696. #pragma segment File
  697. Boolean    DisplayGetFile(StandardFileReply *reply, short typeListLen, SFTypeList typeList)
  698. {
  699.     Point        where = {100, 100};
  700.     SFReply        oldReply;
  701.  
  702.     if (gSystemVersion >= 0x0700)        /* If new standard file available... */
  703.         StandardGetFile(gSFGetFileFilter, typeListLen, typeList, reply);
  704.  
  705.     else {
  706.         SFGetFile(where, "\pSelect a document to open.",
  707.                          gSFGetFileFilter, typeListLen, typeList, nil, &oldReply);
  708.         ConvertOldToNewSFReply(&oldReply, reply);
  709.     }
  710.  
  711.     return(reply->sfGood);
  712. }
  713.  
  714.  
  715.  
  716. /*****************************************************************************/
  717.  
  718.  
  719.  
  720. /* Displays the StandardFile PutFile dialog box. Fills out the passed reply
  721. ** record, and returns the sfGood field as a result. */
  722.  
  723. #pragma segment File
  724. Boolean    DisplayPutFile(StandardFileReply *reply)
  725. {
  726.     Str255        prompt;
  727.     Point        where = {100, 100};
  728.     SFReply        oldReply;
  729.  
  730.     GetIndString(prompt, rFileIOStrings, sSFprompt);
  731.  
  732.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  733.         StandardPutFile(prompt, reply->sfFile.name, reply);
  734.     else {
  735.         SFPutFile(where, prompt, reply->sfFile.name, nil, &oldReply);
  736.         ConvertOldToNewSFReply(&oldReply, reply);
  737.     }
  738.  
  739.     return(reply->sfGood);
  740. }
  741.  
  742.  
  743.  
  744. /*****************************************************************************/
  745.  
  746.  
  747.  
  748. /* Use the resource fork for the designated document file.  This function
  749. ** also returns the old CurResFile, so you can set it back when you are done.
  750. ** Simply call this function, whether or not you have a resource fork.  If
  751. ** there isn't a resource fork, then one will be created.  If there is one,
  752. ** but it isn't open yet, it will be opened.  If it is already opened, it
  753. ** sets it as the current resource fork.  What more do you want? */
  754.  
  755. #define fcbFlgRBit 0x200
  756.  
  757. #pragma segment File
  758. OSErr    UseDocResFile(FileRecHndl frHndl, short *oldRes, char perm)
  759. {
  760.     OSErr        err;
  761.     FSSpec        fss;
  762.     short        res, vrn;
  763.     long        pid;
  764.     FCBPBRec    pb;
  765.     CInfoPBRec    resOpen;
  766.  
  767.     if (oldRes)
  768.         *oldRes = CurResFile();
  769.  
  770.     if ((res = (*frHndl)->fileState.resRefNum) != kInvalRefNum) {
  771.         UseResFile(res);        /* If the resource fork already open, use it. */
  772.         return(ResError());
  773.     }
  774.  
  775.     memset(&pb, 0, sizeof(FCBPBRec));            /* Make most of the param block happy. */
  776.     pb.ioRefNum = res = (*frHndl)->fileState.refNum;
  777.     if (err = PBGetFCBInfoSync(&pb)) return(err);
  778.     if (pb.ioFCBFlags & fcbFlgRBit) {
  779.         (*frHndl)->fileState.resRefNum = res;
  780.         UseResFile(res);
  781.         return(ResError());
  782.     }
  783.  
  784.     fss = (*frHndl)->fileState.fss;
  785.     vrn = fss.vRefNum;
  786.     pid = fss.parID;
  787.  
  788.     memset(&resOpen, 0, sizeof(CInfoPBRec));    /* Make most of the param block happy. */
  789.     resOpen.hFileInfo.ioVRefNum = vrn;
  790.     resOpen.hFileInfo.ioDirID   = pid;
  791.     resOpen.hFileInfo.ioNamePtr = fss.name;
  792.     if (err = PBGetCatInfoSync(&resOpen))    return(err);
  793.     if (resOpen.hFileInfo.ioFlAttrib & 0x04) {
  794.         /* The 0x04 is to look at the bit that says whether or not the resource fork is
  795.         ** already open.  Why did we do this?  To keep from re-opening a resource fork.
  796.         ** Reopening it actually works, but things get a bit ugly when it is closed.  The
  797.         ** one-and-only reference to the open resource fork would get closed if we thought
  798.         ** we opened it.  This keeps us from doing way-bad things later. */
  799.         UseResFile(resOpen.hFileInfo.ioFRefNum);
  800.         return(ResError());
  801.     }
  802.  
  803.     res = HOpenResFile(vrn, pid, fss.name, perm);
  804.         /* Try opening the resource fork. */
  805.  
  806.     if (err = ResError()) {
  807.         if (err != eofErr) return(err);                    /* Some errors we can't handle here. */
  808.         HCreateResFile(vrn, pid, fss.name);                /* No resource fork, so create one.  */
  809.         if (err = ResError()) return(err);                /* Error creating the resource fork. */
  810.         res = HOpenResFile(vrn, pid, fss.name, perm);    /* Now that it exists, open it.  */
  811.         err = ResError();                                /* Return whatever error occurs. */
  812.     }
  813.  
  814.     if (!err) {        /* If no error, then we can use the resource fork. */
  815.         (*frHndl)->fileState.resRefNum = res;
  816.         UseResFile(res);
  817.         err = ResError();
  818.     }
  819.  
  820.     return(err);
  821. }
  822.  
  823.  
  824.  
  825. /*****************************************************************************/
  826.  
  827.  
  828.  
  829. /* If there is a resource fork open for this document, this closes it. */
  830.  
  831. #pragma segment File
  832. OSErr    CloseDocResFile(FileRecHndl frHndl)
  833. {
  834.     short    res;
  835.  
  836.     if ((res = (*frHndl)->fileState.resRefNum) == kInvalRefNum) return(noErr);
  837.         /* If it was never opened, then there's nothing to close. */
  838.  
  839.     if ((*frHndl)->fileState.refNum == res) {
  840.         (*frHndl)->fileState.resRefNum = kInvalRefNum;
  841.         return(noErr);
  842.     }
  843.  
  844.     CloseResFile(res);                                    /* Close the resource fork. */
  845.     (*frHndl)->fileState.resRefNum = kInvalRefNum;        /* Mark it as closed. */
  846.  
  847.     return(ResError());
  848. }
  849.  
  850.  
  851.  
  852. /*****************************************************************************/
  853.  
  854.  
  855.  
  856. #pragma segment File
  857. long    GetModNum(void)
  858. {
  859.     static    modNum = 0;
  860.  
  861.     return(++modNum);
  862. }
  863.  
  864.  
  865.  
  866. /*****************************************************************************/
  867.  
  868.  
  869.  
  870. /* This function returns the state of the document.  If the document
  871. ** is dirty, then true is returned.  If the document is clean, then false
  872. ** is returned. */
  873.  
  874. #pragma segment File
  875. Boolean    GetDocDirty(FileRecHndl frHndl)
  876. {
  877.     if (frHndl) return((*frHndl)->fileState.docDirty);
  878.     return(false);
  879. }
  880.  
  881.  
  882.  
  883. /*****************************************************************************/
  884.  
  885.  
  886.  
  887. /* This function returns the state of the window's document.  If the document
  888. ** is dirty, then true is returned.  If the document is clean, or the window
  889. ** has no document, then false is returned. */
  890.  
  891. #pragma segment File
  892. Boolean    GetWindowDirty(WindowPtr window)
  893. {
  894.     if (IsAppWindow(window)) return(GetDocDirty((FileRecHndl)GetWRefCon(window)));
  895.     return(false);
  896. }
  897.  
  898.  
  899.  
  900. /*****************************************************************************/
  901.  
  902.  
  903.  
  904. #pragma segment File
  905. void    SetDocDirty(FileRecHndl frHndl)
  906. {
  907.     if (frHndl) {
  908.         if (!((*frHndl)->fileState.attributes & kwRuntimeOnlyDoc)) {
  909.             (*frHndl)->fileState.docDirty = true;
  910.             (*frHndl)->fileState.modNum   = GetModNum();
  911.             (*frHndl)->fileState.modTick  = TickCount();
  912.         }
  913.     }
  914. }
  915.  
  916.  
  917.  
  918. /*****************************************************************************/
  919.  
  920.  
  921.  
  922. #pragma segment File
  923. void    SetWindowDirty(WindowPtr window)
  924. {
  925.     if (IsAppWindow(window))
  926.         SetDocDirty((FileRecHndl)GetWRefCon(window));
  927. }
  928.  
  929.  
  930.  
  931. /*****************************************************************************/
  932.  
  933.  
  934.  
  935. /*  The SetDefault function sets the default volume and directory to the volume specified
  936. **  by newVRefNum and the directory specified by newDirID. The current default volume 
  937. **  and directory are returned in oldVRefNum and oldDir and should be used to restore 
  938. **  things to their previous condition *as soon as possible* with the RestoreDefault 
  939. **  function. These two functions are designed to be used as a wrapper around
  940. **  Standard C I/O routines where the location of the file is implied to be the
  941. **  default volume and directory. In other words, this is how you should use these
  942. **  functions:
  943. **
  944. **        err = SetDefault(newVRefNum, newDirID, &oldVRefNum, &oldDirID);
  945. **        if (!err)
  946. **            {
  947. **                -- call the Stdio functions like remove, rename, tmpfile, fopen,   --
  948. **                -- freopen, etc. or non-ANSI extentions like fdopen, fsetfileinfo, --
  949. **                -- create, open, unlink, etc. here!                                   --
  950. **
  951. **                err = RestoreDefault(oldVRefNum, oldDirID);
  952. **            }
  953. **
  954. **  By using these functions as a wrapper, you won't need to open a working directory 
  955. **  (because they use HSetVol) and you won't have to worry about the effects of using
  956. **  HSetVol (documented in Technical Note #140: Why PBHSetVol is Dangerous 
  957. **  and in the Inside Macintosh: Files book in the description of the HSetVol and 
  958. **  PBHSetVol functions) because the default volume/directory is restored before 
  959. **  giving up control to code that might be affected by HSetVol.
  960. ** Use this and the below call instead of the old-style FSpSetWD and FSpResetWD. */
  961.  
  962. #pragma segment File
  963. OSErr    SetDefault(short newVRefNum, long newDirID, short *oldVRefNum, long *oldDirID)
  964. {
  965.     OSErr    err;
  966.  
  967.     err = HGetVol(nil, oldVRefNum, oldDirID);
  968.         /* Get the current default volume/directory. */
  969.  
  970.     if (!err)
  971.         err = HSetVol(nil, newVRefNum, newDirID);
  972.             /* Set the new default volume/directory */
  973.  
  974.     return(err);
  975. }
  976.  
  977.  
  978.  
  979. /*****************************************************************************/
  980.  
  981.  
  982.  
  983. #pragma segment File
  984. OSErr    RestoreDefault(short oldVRefNum, long oldDirID)
  985. {
  986.     OSErr    err;
  987.     short    defaultVRefNum;
  988.     long    defaultDirID;
  989.     long    defaultProcID;
  990.  
  991.     err = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID);
  992.         /* Determine if the default volume was a wdRefNum. */
  993.  
  994.     if (!err) {
  995.         /* Restore the old default volume/directory, one way or the other. */
  996.  
  997.         if (defaultDirID != fsRtDirID)
  998.             err = SetVol(nil, oldVRefNum);
  999.                 /* oldVRefNum was a wdRefNum - use SetVol */
  1000.         else
  1001.             err = HSetVol(nil, oldVRefNum, oldDirID);
  1002.                 /* oldVRefNum was a real vRefNum - use HSetVol */
  1003.     }
  1004.  
  1005.     return(err);
  1006. }
  1007.  
  1008.  
  1009.  
  1010. /*****************************************************************************/
  1011. /*****************************************************************************/
  1012. /*****************************************************************************/
  1013.  
  1014.  
  1015.  
  1016. #pragma segment File
  1017. OSErr    GetFileLocation(short refNum, short *vRefNum, long *dirID, StringPtr fileName)
  1018. {
  1019.     FCBPBRec pb;
  1020.     OSErr err;
  1021.  
  1022.     pb.ioNamePtr = fileName;
  1023.     pb.ioVRefNum = 0;
  1024.     pb.ioRefNum  = refNum;
  1025.     pb.ioFCBIndx = 0;
  1026.  
  1027.     err = PBGetFCBInfoSync(&pb);
  1028.  
  1029.     if (vRefNum)
  1030.         *vRefNum = pb.ioFCBVRefNum;
  1031.     if (dirID)
  1032.         *dirID = pb.ioFCBParID;
  1033.  
  1034.     return(err);
  1035. }
  1036.  
  1037.  
  1038.  
  1039.